/**
 * Created by xc on 17/05/24.
 * 加密用util
 */
var crypto  = require('crypto');
var CONFIG = require('../config');
var path = require('path');
var fs = require('fs');
var CommonUtil = require('./CommonUtil');
var YjxOpenapiAuthModel = require('../../common/yjxMysql/mapping/YjxOpenapiAuthModel');

/**
 * 加密用util
 */
var EncryptUtil = (function() {
    function EncryptUtil() {
    }

    var SJG_DEF_STR_LEN = 5;
    var SJG_SIMP_ENC_KEY = '0123456789abcdef';

    // 简单加密
    EncryptUtil.genRandomStr = function (str) {
        var m = moment(new Date());
        var newDirName = m.format('HH_mm_ss_SSS_') + Math.floor(Math.random() * 100000);
        return newDirName;
    };

    /**
     * 生成随机字符串(数字＋大小写字母)
     */
    EncryptUtil.genRandomStr = function(len) {
        var ret = '';
        var n = Number(len|'0')||0;
        if(n>0) {
            var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
            var maxLen = chars.length;
            for (var i = 0; i < n; i++) {
                ret += chars.charAt(Math.floor(Math.random() * maxLen));
            }
        }
        return ret;
    };

    // md5 字符串
    EncryptUtil.md5 = function(str) {
        return crypto.createHash('md5').update(str).digest('hex');
    };

    // base64 解码
    EncryptUtil.decodeBase64 = function(str) {
        if(str.indexOf(' ') != -1) {
            str = str.replace(/ /g,'+');
        }
        var buffer = new Buffer(str, 'base64');
        return buffer.toString();
    };

    // sha1 字符串
    EncryptUtil.sha1 = function(str){
        return crypto.createHash("sha1").update(str||"").digest("hex");
    };

    // HmacSha1 加密
    EncryptUtil.hmacSha1 = function(secret, str){
        var hmac = crypto.createHmac('sha1', secret);
        hmac.update(str||"");
        return hmac.digest("hex");
    };

    // 随机数[st,ed]
    EncryptUtil.ranNum = function(st,ed){
        return Math.floor(Math.random() * (ed-st+1))+st;
    };

    /**
     * 加密(打乱)字符串 (大写)
     * @param str: 被加密字符串
     * @param decode: 0加密, 1解密
     * @returns {string}
     */
    EncryptUtil.upsetStr = function(str, decode){
        var chars = '6NE9PQRC7TUKXW8YAZ03BS1D5M4OFGH2IJVL';
        var len = chars.length;
        var inStr = (str||'').toUpperCase();
        var outStr = '';
        for(var i=0; i<inStr.length; i++) {
            var idx = chars.indexOf(inStr.charAt(i));
            var newIdx = 0;
            if(decode==1) {
                // 解密
                newIdx = idx-1;
                if(newIdx<0){
                    newIdx = len-1;
                }
            } else {
                // 加密
                newIdx = idx+1;
                if(newIdx>=len){
                    newIdx = 0;
                }
            }
            outStr += chars.charAt(newIdx);
        }
        return outStr;
    };

    // 生成[简单加密]用参数
    EncryptUtil.genSimpleEncryptInfo = function(str) {
        var inStr = str+'';
        if(inStr && inStr.length>0) {
            var ranStr = EncryptUtil.genRandomStr(SJG_DEF_STR_LEN);
            var chkStr = EncryptUtil.md5(inStr + ranStr + SJG_SIMP_ENC_KEY).substr(0, SJG_DEF_STR_LEN);

            var info = {
                q: inStr,
                t: ranStr,
                c: chkStr
            };
            return info;
        }
        return null;
    };

    // 验证[简单加密]参数
    EncryptUtil.chkSimpleEncryptInfo = function(info) {
        if(info) {
            var pStr = info.q||'';
            var ranStr = info.t||'';
            var chkStr = info.c||'';

            if(ranStr && ranStr.length>0 && chkStr && chkStr.length>0) {
                var curChkStr = EncryptUtil.md5(pStr + ranStr + SJG_SIMP_ENC_KEY).substr(0, SJG_DEF_STR_LEN);
                if(curChkStr == chkStr) {
                    return true;
                }
            }
        }
        return false;
    };

    // 根据 由1~5个数字组成的字符串(由逗号连接) 生成加密文本
    // strIn: "123" / “124,12324” / "123,12324,20171202103034" ...
    // out:   "4jv" / "4jvgocw"   / "4jvgocw1paqdmmn0ax" ...
    EncryptUtil.genEncryptNumInfo = function(strIn){
        var strOut = '';
        if(strIn && strIn.length>0) {
            var arr = strIn.split(',');
            if(arr && arr.length<=5) {
                var arrSEP = [
                    {R:26,S:'v'},
                    {R:27,S:'w'},
                    {R:28,S:'x'},
                    {R:29,S:'y'},
                    {R:30,S:'z'}
                ];
                for(var i=0; i<arr.length; i++) {
                    var SEP = arrSEP[i];

                    if(arr[i] && arr[i].length>0) {
                        var num = Number(arr[i]);
                        strOut += num.toString(SEP.R);
                    }
                    strOut += SEP.S;
                }
            }
        }
        return strOut;
    };
    // 函数 [genEncryptNumInfo] 的逆操作
    EncryptUtil.chkEncryptNumInfo = function(strIn){
        var strOut = '';
        if(strIn && strIn.length>0) {
            var arrSEP = [
                {R:26,S:'v'},
                {R:27,S:'w'},
                {R:28,S:'x'},
                {R:29,S:'y'},
                {R:30,S:'z'}
            ];
            for(var i=0;i<arrSEP.length;i++) {
                var SEP=arrSEP[i];
                var idx = strIn.indexOf(SEP.S);
                if(idx>=0) {
                    var numStr = strIn.substr(0,idx);
                    if(i>0) {
                        strOut += ',';
                    }
                    strOut += parseInt(numStr,SEP.R);

                    strIn = strIn.substr(idx+1);
                }
            }
        }
        return strOut;
    };

    /**
     * 生成OpenApi授权key/secret
     * @param authFlg: 权限[保留]
     * @return {"key":"xxxxx", "secret":"yyyyy"}
     */
    EncryptUtil.genOpenApiAuthKeyAndSecret = function(authFlg) {
        var cur = CommonUtil.genCurYearDayTimeStr();
        var ymdh = cur.substr(0, 8);// 年月日时
        var MS = cur.substr(8);// 分秒(4位)

        // KEY
        var T1 = CommonUtil.yearDayTimeStrtoAlphabet(ymdh); // 26进制字符串(4位)
        var RN = CommonUtil.randomNumStr(3); // 随机数(3位)
        var RS = CommonUtil.genNonceStr(2);// 随机字符串(2位)
        var tmpKey = CommonUtil.mix(MS + RN, T1);

        var KEY = ('yjx' + tmpKey + RS).toUpperCase();// 16位

        // SECRET
        var secStr = cur+CommonUtil.genNonceStr(8);
        var SECRET = crypto.createHash('md5').update(secStr,'utf8').digest('hex').toUpperCase();

        return {key: KEY, secret: SECRET};
    };

    /**
     * 生成OpenApi用签名
     * @param secret: 授权secret
     * @param key: 授权key
     * @param expiration: 过期时间点(时间戳)
     * @param nonceStr: 随机字符串(不超过32位)
     * @return signature(大写)
     */
    EncryptUtil.genOpenApiAuthSign = function(secret, key, expiration, nonceStr) {
        nonceStr = nonceStr||"";
        if(nonceStr.length>32){
            nonceStr = nonceStr.substr(0,32);
        }
        var param = "key="+(key||"")+"&expiration="+(expiration||"")+"&nonceStr="+(nonceStr||"");
        var sign = EncryptUtil.hmacSha1(secret, param);
        return sign.toUpperCase();
    };

    /**
     * 生成OpenApi授权令牌
     * @param key: 授权KEY
     * @param secret: 授权SECRET
     * @param userId: 被授权用户
     * @param period: token有效时长,单位秒[300~2592000]
     * @return TOKEN
     */
    EncryptUtil.genOpenApiAuthToken = function(key, secret, userId, period, callback) {

        //var strCurTime = CommonUtil.genCurYearDayTimeStr('YYYYMMDDHHmmss');
        var curTime = Date.now();
        var expDur = Number(period||'0');
        if(expDur<300 || expDur>2592000) {
            return callback('申请时长无效', null);
        }

        if(key && key.length==16 && secret && secret.length>=32 && Number(userId||'0')>0) {

            // 版本号(36进制 2位): 例 v1.1 ==> "11"
            var verB = 1;// 大版本号
            var verS = 0;// 小版本号
            var VER = verB.toString(36)+verS.toString(36);

            // 区块信息
            // 区块1: KEY (16位)
            // 区块2: userId (转35进制, 4~13位)
            // 区块3: 创建时间点的时间戳 (转34进制, 8位)
            // 区块4: token有效时长,单位秒 (转33进制, 2~5位)
            // 区块5~7: 保留区块 (暂填充1~10位随机字符串)
            // 区块8: [区块1~4]+[SECRET]+[区块5～7] 的MD5值 (16进制, 32位)
            var B1 = EncryptUtil.upsetStr(key||"");
            var B2 = Number(userId||"0").toString(35);
            var B3 = (curTime*1).toString(34);
            var B4 = (expDur*1).toString(33);
            var B5 = CommonUtil.randomString(EncryptUtil.ranNum(1,10));
            var B6 = CommonUtil.randomString(EncryptUtil.ranNum(1,10));
            var B7 = CommonUtil.randomString(EncryptUtil.ranNum(1,10));
            var B8 = EncryptUtil.md5((B1+B2+B3+B4+secret+B5+B6+B7).toUpperCase());// 以大写算md5

            // 区块长度信息
            // 16进制, 共16位, 每2位表示一个区块长度
            // 如有空白区块, 长度信息填充 g~z 随机字符串(即不与16进制字符冲突)
            // var TMP_CHARS = 'HIJKLMNOPQRSTUVWXYZhijklmnopqrstuvwxyz';
            // CommonUtil.randomString2(2, TMP_CHARS);
            var lenB1 = toLenNumStr(B1.length.toString(16),2);
            var lenB2 = toLenNumStr(B2.length.toString(16),2);
            var lenB3 = toLenNumStr(B3.length.toString(16),2);
            var lenB4 = toLenNumStr(B4.length.toString(16),2);
            var lenB5 = toLenNumStr(B5.length.toString(16),2);
            var lenB6 = toLenNumStr(B6.length.toString(16),2);
            var lenB7 = toLenNumStr(B7.length.toString(16),2);
            var lenB8 = toLenNumStr(B8.length.toString(16),2);

            // 拼接TOKEN
            var TOKEN = VER+""
                +lenB1+lenB2+lenB3+lenB4+lenB5+lenB6+lenB7+lenB8
                +B1+B2+B3+B4+B5+B6+B7+B8;
            if(TOKEN.length<128) {
                // 填充满128位
                TOKEN += CommonUtil.randomString(128-TOKEN.length);
            }

            return callback(null, {token:TOKEN.toUpperCase()});// 转大写

        } else {
            return callback('参数错误', null);
        }

        function toLenNumStr(inStr, len){
            var str = inStr||'';
            if(len<=inStr.length) {
                str = str.substr(0,len);
            } else {
                var fix = len-inStr.length;
                for(var i=0;i<fix;i++) {
                    str = '0'+str;
                }
            }
            return str;
        }
    };

    /**
     * 验证OpenApi授权令牌
     * @param token
     * @returns {ver, key, userId, crtTime(有效起始时间的时间戳), expTime(有效截止时间的时间戳)}
     */
    EncryptUtil.chkOpenApiAuthToken = function(token, callback) {

        var TOKEN = token||'';
        if(token && token.length>=128) {

            // 版本号(36进制 2位): 例 v1.1 ==> "11"
            var verB = parseInt(TOKEN.substr(0,1), 36);
            var verS = parseInt(TOKEN.substr(1,1), 36);
            var VER = verB+"."+verS;

            // 区块长度信息
            // 16进制, 共16位, 每2位表示一个区块长度
            var lenB1 = parseInt(TOKEN.substr(2,2),16);
            var lenB2 = parseInt(TOKEN.substr(4,2),16);
            var lenB3 = parseInt(TOKEN.substr(6,2),16);
            var lenB4 = parseInt(TOKEN.substr(8,2),16);
            var lenB5 = parseInt(TOKEN.substr(10,2),16);
            var lenB6 = parseInt(TOKEN.substr(12,2),16);
            var lenB7 = parseInt(TOKEN.substr(14,2),16);
            var lenB8 = parseInt(TOKEN.substr(16,2),16);

            // 区块信息
            // 区块1: KEY (乱序加密, 16位)
            // 区块2: userId (转35进制, 4~13位)
            // 区块3: 创建时间点的时间戳 (转34进制, 8位)
            // 区块4: token有效时长,单位秒 (转33进制, 2~5位)
            // 区块5~7: 保留区块 (暂填充1~10位随机字符串)
            // 区块8: [区块1~4]+[SECRET]+[区块5～7] 的MD5值 (16进制, 32位)
            var IDX = 18;
            var B1 = TOKEN.substr(IDX,lenB1);
            var KEY = EncryptUtil.upsetStr(B1,1);

            IDX+=lenB1;
            var B2 = TOKEN.substr(IDX,lenB2);
            var userId = parseInt(B2, 35);

            IDX+=lenB2;
            var B3 = TOKEN.substr(IDX,lenB3);
            var crtTime = parseInt(B3, 34);

            IDX+=lenB3;
            var B4 = TOKEN.substr(IDX,lenB4);
            var expDur = parseInt(B4, 33);
            var expTime = crtTime+expDur*1000;

            IDX+=lenB4;
            var B5 = TOKEN.substr(IDX,lenB5);
            IDX+=lenB5;
            var B6 = TOKEN.substr(IDX,lenB6);
            IDX+=lenB6;
            var B7 = TOKEN.substr(IDX,lenB7);

            IDX+=lenB7;
            var B8 = TOKEN.substr(IDX,lenB8);

            var ent = new YjxOpenapiAuthModel({
                key: KEY,
                user_id: userId,
                del_flg: 0
            });
            ent.findFromDB(function(err, findRet){
                if(err) {
                    return callback(err, null);
                }

                if(findRet && findRet.length>0) {
                    //
                    var SECERT = findRet[0].secret||'';
                    var chkMd5 = EncryptUtil.md5((B1+B2+B3+B4+SECERT+B5+B6+B7).toUpperCase());
                    if(B8==chkMd5) {
                        return callback(null,{
                            ver: VER,
                            key: KEY,
                            userId: userId,
                            crtTime: crtTime,
                            expTime: expTime
                        });

                    } else {
                        return callback('无效token', null);
                    }

                } else {
                    return callback('无效用户', null);
                }
            });

        } else {
            return callback('无效token', null);
        }
    };


    return EncryptUtil;
})();

module.exports = EncryptUtil;